{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "f28455fa",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "\n",
    "# data visualization\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "%matplotlib inline\n",
    "\n",
    "import tensorflow as tf\n",
    "from sklearn.preprocessing import MinMaxScaler\n",
    "from keras.models import Sequential\n",
    "from keras.layers import LSTM,Dense,Dropout\n",
    "from sklearn.metrics import mean_squared_error,mean_absolute_error,r2_score\n",
    "\n",
    "import math \n",
    "import os "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "506cd016",
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签\n",
    "plt.rcParams['axes.unicode_minus']=False #用来正常显示负号\n",
    "sns.set(font='SimHei')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "2fd9ce76",
   "metadata": {},
   "outputs": [],
   "source": [
    "df= pd.read_csv('../dataset/min.csv')  # 读取股票文件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "61c70e7a",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>时间</th>\n",
       "      <th>开盘</th>\n",
       "      <th>收盘</th>\n",
       "      <th>最高</th>\n",
       "      <th>最低</th>\n",
       "      <th>成交量</th>\n",
       "      <th>成交额</th>\n",
       "      <th>最新价</th>\n",
       "      <th>code</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>2021-11-19 09:30:00</td>\n",
       "      <td>17.80</td>\n",
       "      <td>17.80</td>\n",
       "      <td>17.80</td>\n",
       "      <td>17.80</td>\n",
       "      <td>4127</td>\n",
       "      <td>7346060</td>\n",
       "      <td>17.80</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>2021-11-19 09:30:00</td>\n",
       "      <td>19.01</td>\n",
       "      <td>19.01</td>\n",
       "      <td>19.01</td>\n",
       "      <td>19.01</td>\n",
       "      <td>1718</td>\n",
       "      <td>3265918</td>\n",
       "      <td>19.01</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>2021-11-19 09:30:00</td>\n",
       "      <td>18.84</td>\n",
       "      <td>18.84</td>\n",
       "      <td>18.84</td>\n",
       "      <td>18.84</td>\n",
       "      <td>568</td>\n",
       "      <td>1070112</td>\n",
       "      <td>18.84</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>2021-11-19 09:30:00</td>\n",
       "      <td>4.12</td>\n",
       "      <td>4.12</td>\n",
       "      <td>4.12</td>\n",
       "      <td>4.12</td>\n",
       "      <td>29</td>\n",
       "      <td>11750</td>\n",
       "      <td>4.12</td>\n",
       "      <td>6</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>2021-11-19 09:30:00</td>\n",
       "      <td>2.14</td>\n",
       "      <td>2.14</td>\n",
       "      <td>2.14</td>\n",
       "      <td>2.14</td>\n",
       "      <td>165</td>\n",
       "      <td>35310</td>\n",
       "      <td>2.14</td>\n",
       "      <td>8</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                    时间     开盘     收盘     最高     最低   成交量      成交额    最新价  code\n",
       "0  2021-11-19 09:30:00  17.80  17.80  17.80  17.80  4127  7346060  17.80     1\n",
       "1  2021-11-19 09:30:00  19.01  19.01  19.01  19.01  1718  3265918  19.01     2\n",
       "2  2021-11-19 09:30:00  18.84  18.84  18.84  18.84   568  1070112  18.84     4\n",
       "3  2021-11-19 09:30:00   4.12   4.12   4.12   4.12    29    11750   4.12     6\n",
       "4  2021-11-19 09:30:00   2.14   2.14   2.14   2.14   165    35310   2.14     8"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "524798d2",
   "metadata": {},
   "outputs": [],
   "source": [
    "df = df.loc[df['code'] == 600031]\n",
    "df.drop(['code'],axis=1,inplace=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "5022e477",
   "metadata": {},
   "outputs": [],
   "source": [
    "df.set_index('时间',inplace=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "9840770d",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>开盘</th>\n",
       "      <th>收盘</th>\n",
       "      <th>最高</th>\n",
       "      <th>最低</th>\n",
       "      <th>成交量</th>\n",
       "      <th>成交额</th>\n",
       "      <th>最新价</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>时间</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:30:00</th>\n",
       "      <td>21.66</td>\n",
       "      <td>21.66</td>\n",
       "      <td>21.66</td>\n",
       "      <td>21.66</td>\n",
       "      <td>3208</td>\n",
       "      <td>6948528</td>\n",
       "      <td>21.660</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:31:00</th>\n",
       "      <td>21.65</td>\n",
       "      <td>21.62</td>\n",
       "      <td>21.69</td>\n",
       "      <td>21.60</td>\n",
       "      <td>11702</td>\n",
       "      <td>25326434</td>\n",
       "      <td>21.647</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:32:00</th>\n",
       "      <td>21.61</td>\n",
       "      <td>21.65</td>\n",
       "      <td>21.66</td>\n",
       "      <td>21.61</td>\n",
       "      <td>7952</td>\n",
       "      <td>17191749</td>\n",
       "      <td>21.637</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:33:00</th>\n",
       "      <td>21.65</td>\n",
       "      <td>21.73</td>\n",
       "      <td>21.75</td>\n",
       "      <td>21.65</td>\n",
       "      <td>5002</td>\n",
       "      <td>10861705</td>\n",
       "      <td>21.651</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:34:00</th>\n",
       "      <td>21.73</td>\n",
       "      <td>21.69</td>\n",
       "      <td>21.73</td>\n",
       "      <td>21.66</td>\n",
       "      <td>6512</td>\n",
       "      <td>14127838</td>\n",
       "      <td>21.659</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                        开盘     收盘     最高     最低    成交量       成交额     最新价\n",
       "时间                                                                      \n",
       "2021-11-19 09:30:00  21.66  21.66  21.66  21.66   3208   6948528  21.660\n",
       "2021-11-19 09:31:00  21.65  21.62  21.69  21.60  11702  25326434  21.647\n",
       "2021-11-19 09:32:00  21.61  21.65  21.66  21.61   7952  17191749  21.637\n",
       "2021-11-19 09:33:00  21.65  21.73  21.75  21.65   5002  10861705  21.651\n",
       "2021-11-19 09:34:00  21.73  21.69  21.73  21.66   6512  14127838  21.659"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1fab15fd",
   "metadata": {},
   "source": [
    "# 添加特征"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7f2caa73",
   "metadata": {},
   "source": [
    "* 涨跌额"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "a358daef",
   "metadata": {},
   "outputs": [],
   "source": [
    "datalist = list()\n",
    "for i in range(len(df)-1):\n",
    "    datalist.append(df.iloc[i,1]-df.iloc[i+1,0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "bc4916a0",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "df = df.iloc[:-1]\n",
    "df.loc[:,'涨跌额'] = datalist"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "549ab12f",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>开盘</th>\n",
       "      <th>收盘</th>\n",
       "      <th>最高</th>\n",
       "      <th>最低</th>\n",
       "      <th>成交量</th>\n",
       "      <th>成交额</th>\n",
       "      <th>最新价</th>\n",
       "      <th>涨跌额</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>时间</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:30:00</th>\n",
       "      <td>21.66</td>\n",
       "      <td>21.66</td>\n",
       "      <td>21.66</td>\n",
       "      <td>21.66</td>\n",
       "      <td>3208</td>\n",
       "      <td>6948528</td>\n",
       "      <td>21.660</td>\n",
       "      <td>0.01</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:31:00</th>\n",
       "      <td>21.65</td>\n",
       "      <td>21.62</td>\n",
       "      <td>21.69</td>\n",
       "      <td>21.60</td>\n",
       "      <td>11702</td>\n",
       "      <td>25326434</td>\n",
       "      <td>21.647</td>\n",
       "      <td>0.01</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:32:00</th>\n",
       "      <td>21.61</td>\n",
       "      <td>21.65</td>\n",
       "      <td>21.66</td>\n",
       "      <td>21.61</td>\n",
       "      <td>7952</td>\n",
       "      <td>17191749</td>\n",
       "      <td>21.637</td>\n",
       "      <td>0.00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:33:00</th>\n",
       "      <td>21.65</td>\n",
       "      <td>21.73</td>\n",
       "      <td>21.75</td>\n",
       "      <td>21.65</td>\n",
       "      <td>5002</td>\n",
       "      <td>10861705</td>\n",
       "      <td>21.651</td>\n",
       "      <td>0.00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:34:00</th>\n",
       "      <td>21.73</td>\n",
       "      <td>21.69</td>\n",
       "      <td>21.73</td>\n",
       "      <td>21.66</td>\n",
       "      <td>6512</td>\n",
       "      <td>14127838</td>\n",
       "      <td>21.659</td>\n",
       "      <td>0.00</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                        开盘     收盘     最高     最低    成交量       成交额     最新价   涨跌额\n",
       "时间                                                                            \n",
       "2021-11-19 09:30:00  21.66  21.66  21.66  21.66   3208   6948528  21.660  0.01\n",
       "2021-11-19 09:31:00  21.65  21.62  21.69  21.60  11702  25326434  21.647  0.01\n",
       "2021-11-19 09:32:00  21.61  21.65  21.66  21.61   7952  17191749  21.637  0.00\n",
       "2021-11-19 09:33:00  21.65  21.73  21.75  21.65   5002  10861705  21.651  0.00\n",
       "2021-11-19 09:34:00  21.73  21.69  21.73  21.66   6512  14127838  21.659  0.00"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "771974f7",
   "metadata": {},
   "source": [
    "* SVM支持向量机预测"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "a1792930",
   "metadata": {},
   "outputs": [],
   "source": [
    "df_for_svm = df.copy()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "74722dc0",
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn import svm\n",
    "model = svm.SVC(C=0.6, kernel='rbf', gamma=0.001)\n",
    "# 添加一列涨跌数据\n",
    "datalist = list()\n",
    "datalist.append(1)\n",
    "for i in range(1,len(df_for_svm)):\n",
    "    if df_for_svm.iloc[i,0] > df_for_svm.iloc[i-1,1]:\n",
    "        datalist.append(1)\n",
    "    else:\n",
    "        datalist.append(0)\n",
    "df_for_svm.loc[:,'涨跌'] = datalist"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "e687252b",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>开盘</th>\n",
       "      <th>收盘</th>\n",
       "      <th>最高</th>\n",
       "      <th>最低</th>\n",
       "      <th>成交量</th>\n",
       "      <th>成交额</th>\n",
       "      <th>最新价</th>\n",
       "      <th>涨跌额</th>\n",
       "      <th>涨跌</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>时间</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:30:00</th>\n",
       "      <td>21.66</td>\n",
       "      <td>21.66</td>\n",
       "      <td>21.66</td>\n",
       "      <td>21.66</td>\n",
       "      <td>3208</td>\n",
       "      <td>6948528</td>\n",
       "      <td>21.660</td>\n",
       "      <td>0.01</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:31:00</th>\n",
       "      <td>21.65</td>\n",
       "      <td>21.62</td>\n",
       "      <td>21.69</td>\n",
       "      <td>21.60</td>\n",
       "      <td>11702</td>\n",
       "      <td>25326434</td>\n",
       "      <td>21.647</td>\n",
       "      <td>0.01</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:32:00</th>\n",
       "      <td>21.61</td>\n",
       "      <td>21.65</td>\n",
       "      <td>21.66</td>\n",
       "      <td>21.61</td>\n",
       "      <td>7952</td>\n",
       "      <td>17191749</td>\n",
       "      <td>21.637</td>\n",
       "      <td>0.00</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:33:00</th>\n",
       "      <td>21.65</td>\n",
       "      <td>21.73</td>\n",
       "      <td>21.75</td>\n",
       "      <td>21.65</td>\n",
       "      <td>5002</td>\n",
       "      <td>10861705</td>\n",
       "      <td>21.651</td>\n",
       "      <td>0.00</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:34:00</th>\n",
       "      <td>21.73</td>\n",
       "      <td>21.69</td>\n",
       "      <td>21.73</td>\n",
       "      <td>21.66</td>\n",
       "      <td>6512</td>\n",
       "      <td>14127838</td>\n",
       "      <td>21.659</td>\n",
       "      <td>0.00</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                        开盘     收盘     最高     最低    成交量       成交额     最新价  \\\n",
       "时间                                                                         \n",
       "2021-11-19 09:30:00  21.66  21.66  21.66  21.66   3208   6948528  21.660   \n",
       "2021-11-19 09:31:00  21.65  21.62  21.69  21.60  11702  25326434  21.647   \n",
       "2021-11-19 09:32:00  21.61  21.65  21.66  21.61   7952  17191749  21.637   \n",
       "2021-11-19 09:33:00  21.65  21.73  21.75  21.65   5002  10861705  21.651   \n",
       "2021-11-19 09:34:00  21.73  21.69  21.73  21.66   6512  14127838  21.659   \n",
       "\n",
       "                      涨跌额  涨跌  \n",
       "时间                             \n",
       "2021-11-19 09:30:00  0.01   1  \n",
       "2021-11-19 09:31:00  0.01   0  \n",
       "2021-11-19 09:32:00  0.00   0  \n",
       "2021-11-19 09:33:00  0.00   0  \n",
       "2021-11-19 09:34:00  0.00   0  "
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df_for_svm.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d77143f6",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 修改特征\n",
    "for i in range(len(df_for_svm))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "64188b2a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "SVC(C=0.6, gamma=0.001)"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X_train = df_for_svm.iloc[:,:-1].values\n",
    "y_train = df_for_svm.iloc[:,-1].values\n",
    "model.fit(X_train[:-1], y_train[1:])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "424a155c",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((237, 8), (237,))"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X_train.shape,y_train.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "d84ab508",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 将数据按周期分割成多个组\n",
    "datalist = list()\n",
    "for i in range(len(df_for_svm)):\n",
    "    X = df_for_svm.iloc[i,:-1].values\n",
    "    Y = model.predict(X.reshape(1, len(X)))\n",
    "    datalist.append(Y[0])\n",
    "df_for_svm.loc[:,'svm预测'] = datalist"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "166aaa82",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>开盘</th>\n",
       "      <th>收盘</th>\n",
       "      <th>最高</th>\n",
       "      <th>最低</th>\n",
       "      <th>成交量</th>\n",
       "      <th>成交额</th>\n",
       "      <th>最新价</th>\n",
       "      <th>涨跌额</th>\n",
       "      <th>涨跌</th>\n",
       "      <th>svm预测</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>时间</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:30:00</th>\n",
       "      <td>21.66</td>\n",
       "      <td>21.66</td>\n",
       "      <td>21.66</td>\n",
       "      <td>21.66</td>\n",
       "      <td>3208</td>\n",
       "      <td>6948528</td>\n",
       "      <td>21.660</td>\n",
       "      <td>0.01</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:31:00</th>\n",
       "      <td>21.65</td>\n",
       "      <td>21.62</td>\n",
       "      <td>21.69</td>\n",
       "      <td>21.60</td>\n",
       "      <td>11702</td>\n",
       "      <td>25326434</td>\n",
       "      <td>21.647</td>\n",
       "      <td>0.01</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:32:00</th>\n",
       "      <td>21.61</td>\n",
       "      <td>21.65</td>\n",
       "      <td>21.66</td>\n",
       "      <td>21.61</td>\n",
       "      <td>7952</td>\n",
       "      <td>17191749</td>\n",
       "      <td>21.637</td>\n",
       "      <td>0.00</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:33:00</th>\n",
       "      <td>21.65</td>\n",
       "      <td>21.73</td>\n",
       "      <td>21.75</td>\n",
       "      <td>21.65</td>\n",
       "      <td>5002</td>\n",
       "      <td>10861705</td>\n",
       "      <td>21.651</td>\n",
       "      <td>0.00</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:34:00</th>\n",
       "      <td>21.73</td>\n",
       "      <td>21.69</td>\n",
       "      <td>21.73</td>\n",
       "      <td>21.66</td>\n",
       "      <td>6512</td>\n",
       "      <td>14127838</td>\n",
       "      <td>21.659</td>\n",
       "      <td>0.00</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                        开盘     收盘     最高     最低    成交量       成交额     最新价  \\\n",
       "时间                                                                         \n",
       "2021-11-19 09:30:00  21.66  21.66  21.66  21.66   3208   6948528  21.660   \n",
       "2021-11-19 09:31:00  21.65  21.62  21.69  21.60  11702  25326434  21.647   \n",
       "2021-11-19 09:32:00  21.61  21.65  21.66  21.61   7952  17191749  21.637   \n",
       "2021-11-19 09:33:00  21.65  21.73  21.75  21.65   5002  10861705  21.651   \n",
       "2021-11-19 09:34:00  21.73  21.69  21.73  21.66   6512  14127838  21.659   \n",
       "\n",
       "                      涨跌额  涨跌  svm预测  \n",
       "时间                                    \n",
       "2021-11-19 09:30:00  0.01   1      0  \n",
       "2021-11-19 09:31:00  0.01   0      0  \n",
       "2021-11-19 09:32:00  0.00   0      0  \n",
       "2021-11-19 09:33:00  0.00   0      0  \n",
       "2021-11-19 09:34:00  0.00   0      0  "
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df_for_svm.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "160539e0",
   "metadata": {},
   "source": [
    "## 数据检查"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "54a2df6e",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Function to check the missing percent of a DatFrame;\n",
    "def check_missing_data(df):\n",
    "    total = df.isnull().sum().sort_values(ascending = False)\n",
    "    percent = round(df.isnull().sum().sort_values(ascending = False) * 100 /len(df),2)\n",
    "    return pd.concat([total, percent], axis=1, keys=['Total','Percent'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "862a721d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Total</th>\n",
       "      <th>Percent</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>开盘</th>\n",
       "      <td>0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>收盘</th>\n",
       "      <td>0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>最高</th>\n",
       "      <td>0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>最低</th>\n",
       "      <td>0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>成交量</th>\n",
       "      <td>0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>成交额</th>\n",
       "      <td>0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>最新价</th>\n",
       "      <td>0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>涨跌额</th>\n",
       "      <td>0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "     Total  Percent\n",
       "开盘       0      0.0\n",
       "收盘       0      0.0\n",
       "最高       0      0.0\n",
       "最低       0      0.0\n",
       "成交量      0      0.0\n",
       "成交额      0      0.0\n",
       "最新价      0      0.0\n",
       "涨跌额      0      0.0"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "check_missing_data(df)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "350f50c5",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXoAAAD/CAYAAAD/qh1PAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8/fFQqAAAACXBIWXMAAAsTAAALEwEAmpwYAAA6cUlEQVR4nO3deVhTV/748XcIBhEEd1yqVh3UsVhA+xX9tXWpOmilWixCqUXxi0ofN8C1Ou10OlD39SlT6l6kVkdxGR2XLqKotNa6gDBIHXcQFxAoEsAAye8PvqYyoCQaJMTPy+c+ci8n534SwieHc889R6HT6XQIIYSwWFa1HYAQQoiaJYleCCEsnCR6IYSwcJLohRDCwkmiF0IICyeJXgghLJwkeiGEsHCS6IUQwoyUlJQwceJEfv7558eWW7NmDd7e3gQFBZGdnf3YspLohRDCTJSWljJp0iQyMzMfW+7MmTPExcURGxvL+PHjWbVq1WPLS6IXQogalJ+fT0ZGRqUtPz+/yvLh4eG4uLg8ts6EhAS8vLxQKpX07t2bxMTEx5a3ftLgzU1J9uXaDgHKSmo7gnIKM/j8tlLWdgQA+PSYVtshUM8cfh7AptntajsEnD86XNshAHAj999P9fiSO/8xuGz0Pw4SGRlZ6fiUKVOYOnVqhWPW1ta0bNmy2jrVajXdunUDQKFQUFhY+NjyFpPohRDimdFpDS46duxYvL29Kx13cHB44tPb29tTVFSk3y8oKHhseUn0QghhLK3hid7BweGpknpV3NzcOHjwIF5eXly9epXGjRs/trx5/E0phBB1iE6nNXh7WlFRUfz0008VjvXp04eLFy8SERFBWFgYAQEBj61DYSnTFEsf/UPMoU9Y+uj1pI/+d5bSR6/JSDa4rOqF7k91rkfGoNEQFxdH8+bN6dmz52PLSteNEEIYywQt9aelUqkYMmSIQWUl0QshhLHM5a93A5lFotfpdCgUitoOQwghDGPExVhzYPLOQ41GQ2lpaZXfKysrQ6PRVDo+c+ZMDh82j747IYSozrO8GGsKJm/Rr1y5kp9++oni4mJycnJo3749RUVF3Lp1i7Zt2+Lk5ERUVBQA0dHRREdH4+joyBdffEFUVBRlZWW0aNFCX0YIIcxOHWvRmzzRz549G4Cff/6ZrVu3smLFCpKTk4mMjGT16tUVyiqVSnx8fAgICCAsLIywsDBatWrFRx99ZOqwhBDCdMykpW6oWumjP3fuHH/961/Jy8ujrKyMI0eOUFpayl/+8hd0Oh0ZGRn4+PgwY8YM+vTpUxshCiHEoz3PF2P37dvHunXrsLa2Rq1Wc/fuXXx9ffVdN76+vpSUlBASEsK2bduYOnUqwcHB3Lx5kxs3buDr60tubi4rV65k6dKlpgxNCCFM53nuuunXrx99+vTBwcGBvXv3cuHCBebMmaPvuvnyyy9Rq9WoVCri4uLQaDS4ubnh5ubGDz/8gFqtZuLEiYwePRql0jxuuBFCiEqe564be3t7/dfx8fEMHTq0wvcVCoW+jK2tLfn5+fj7+1co06RJEw4cOECXLl3w8PAwZXhCCGEadaxFXyP3ZqelpXHq1Cn69u37yDL37t3Dw8ODLVu2YGNjU+F/FxcX1Gp1TYQmhBBPTacrM3gzBya/GPvrr78yadIk5s2bh62tLQBarZb/nlLHyurxnzFyA5UQwmw9z103paWlREVFMWHCBN5880398ZKSEsrKfv9kW7ZsGUeOHEGj0ZCSksKlS5cIDAzU/5+RkcGPP/7I6dOnmTlzpilDFEKIp1dW9U2h5kpmrzQlcxlyZQ6zJcrslXoye+XvLGX2yuJfdhhctv7/vPNU5zIFs5jrRggh6pTnuetGCCGeC3Vs1I0keiGEMJa06IUQwsI9YoZecyWJXgghjGQu4+MNJYleCCGMJX30Qghh4aSPXgghLJy06GuJOdyspKxX2xGYD6159GHaKWr/Z6LETKbzKKn935FSM3lfPDVp0QshhIWrY1MgSKIXQghjSdeNEEJYOEn0Qghh4aSPXgghLJy06IUQwsJJi14IISycjLqpTK1WY2dn98jv63Q6WTpQCFF31LGumxpb+uatt94CypcRHDhwIHfv3n1k2ZkzZ3L4sHmsPCOEENXSag3fzIBJW/Q3b94kPT2dXr16YW9vD8CxY8d49dVXadq0qb7cgxZ8dHQ00dHRODo68sUXXxAVFUVZWRktWrQgKirKlKEJIYTp1LEVWE3aor969SoHDx6scGzbtm1cv34df39/PDw8GDlyJFu2bAFAqVTi4+PDpk2bcHR05JNPPmHt2rXSjSOEMG811KJfs2YN3t7eBAUFkZ2dXWWZwsJCpkyZQkBAAO+++y7nz5+vtl6TtuitrKxQKn9fFPrChQukpaWxdu1anJ2d8fHxYdu2baSkpDBy5Ejy8vIoKyvjyJEjlJaW8pe//AWdTkdGRgY+Pj7MmDGDPn36mDJEIYR4ejVwMfbMmTPExcURGxvLyZMnWbVqFeHh4ZXK7dq1C1dXVyZMmMDZs2dZsWIFa9aseWzdNXoxduPGjfj5+REdHU14eDharRYrKytcXFzYtm0bU6dOJTg4mJs3b3Ljxg18fX3Jzc1l5cqVLF26tCZDE0KIJ2dESz0/P5/8/PxKxx0cHHBwcNDvJyQk4OXlhVKppHfv3syfP7/K+po2bcrp06cpLCzk7NmzdOzYsdoYajTRh4eHo9PpGDlyJGlpaTg7OwPlLf8ffvgBjUaDm5sbbm5u/PDDD6jVaiZOnMjo0aMr/GUghBBmxYg++ujoaCIjIysdnzJlClOnTtXvq9VqunXrBoBCoaCwsLDK+l599VW2b9/Opk2b+M9//sPYsWOrjcGkif7XX3/l0KFDXL9+HY1Gg7V1efWurq7MnTuXkJAQfVlbW1vy8/Px9/evUEeTJk04cOAAXbp0wcPDw5ThCSGEaRjRoh87dize3t6Vjj/cmgewt7enqKhIv19QUFBlfevWrcPf359Bgwah1WoZMWIEe/fufWwMJr0YO2DAAFavXs3q1atRqVT643/4wx+4cuUKr7zyiv7YvXv38PDwYMuWLdjY2FT438XFBbVabcrQhBDCdIy4GOvg4MALL7xQafvvRO/m5saJEyeA8oEtjRs3rvLUGo2G1NRUAFJSUgzKlSZN9G3bttV3z+h0OsrKyvjqq6/YtWsXc+fOZfz48Zw4cQKdToeV1eNPLSNvhBBmS6c1fDNQnz59uHjxIhEREYSFhREQEMD27dsrtdYDAgL4+eefcXNzIzQ0lLlz51Zbd4310RcWFjJ79mzq1avH5s2bsbe3p2vXrkRERKBUKiksLESj0ZCSksKlS5cIDAzU/5+RkcGPP/7I6dOnmTlzZk2FKIQQT0RXavqVspRKJZs2bSIuLo6hQ4fSs2fPKsu1bt2azZs3G1V3jSX6PXv2UFpaqu+nh/I/TWJjY2vqlEII8WzU0KRmKpWKIUOGmLzeGh1183CSF0IIi6GtW3fGSiYWQghjmckcNoaSRC+EEMaSRC+EEBaujk1qJoleCCGMVQOjbmqSJHohhDCWLCUohBAWTkbd1BJFjS2WJeowO0Xtv8Wtkbu8LY1OLsYKIYSFkxa9EEJYuDK5GCuEEJZNum6EEMLCSdeNEEJYOBleKYQQFk5a9EIIYdlkeOUTunfvHg0bNqztMIQQonqlkuirpdFoKCgo0M9Xf/PmTcaMGcN3332nX0KwtLQUe3v7CmvPCiGEWZA+evDz8yMxMbHS8R49erBlyxauXr3K2rVrUSqV+u8NGDCABQsW6Pe1Wi3jx4+nc+fONRGiEEI8OemjL1/Ye9GiRRUW+C4uLmbPnj0AdO7cmSVLlhATE8OhQ4cqPd7Pz4+hQ4fWRGhCCPHUdJLoYd68eRQUFFQ6PmfOnAr76enpDB48mJdffll/LCEhgaysrJoISwghTON5TvRJSUlERERQUFCAk5MTOTk52NraYmtrqy+jVqtZunQp7du3p2/fvqSmpvLTTz/pv29lZYWbm5spwxJCCNN6nkfduLq68vnnnxMSEoKnpydHjx5lwIABaDQafX+8p6cnTZo04d1336V+/fpV1vPjjz+Sl5fH1q1bH1lGCCFqjYy6AQcHB5ydnUlNTcXR0ZGYmBhCQ0NZtmwZI0eOBKCwsJCtW7fyyy+/cPXqVf1jnZyc6Nu3LyNHjqxwsVYIIcyFro4tJVgjk7inpqayatUqEhISaNSoET169ECj0dChQwdsbGwA9Bdq9+/fT6tWrXB1daVDhw588803+noevpgrhBBmQ6szfDMDJm3R379/n/j4eJo1a4aLiwsA+/btY9q0aXh6ejJ16lR92QefiG3atGH16tX64w8uzNa1T0whxHPETBK4oUya6FUqFY6OjixfvpwOHToQGRlJu3btWLhwId988w2JiYnMnj2biIgISktLARg/fjzjx4+vUM+SJUtQKBT6G6qEEMKc1LXhlQqdGTadS0pKqFevnnGPufOfGorGCFZyTUFPax4LM0zqNa+2QzCbpQSXhTau7RDo8El8bYcAwO3f0p7q8b8FDDS4rGNM5XuFnjWzbDIbm+SFEOJZqmsterNM9EIIYdYk0QshhIWrW8PoJdELIYSxpOtGCCEsXR1r0dfIDVNCCGHJdKU6gzdjrFmzBm9vb4KCgsjOzn5s2RMnThAUFGTQPUeS6IUQwkg6reGboc6cOUNcXByxsbGMHz+eVatWPbLsb7/9Rnh4OOHh4QbNIGA5XTfmMIbdTMaOmwVz+HkA18sqT5f9rCnNZSoPZbPajsBypjUxIoHn5+eTn59f6biDgwMODg76/YSEBLy8vFAqlfTu3Zv58+c/ss5PPvmEli1b8t133+Hp6UmrVq0eG4PlJHohhHhGjGmpR0dHExkZWen4lClTKkwLo1ar6datG1D+gVhYWFhlfSdPnuT8+fOsW7eOwsJCJk6cSHR0NE2aNHlkDJLohRDCWEYk+rFjx+Lt7V3p+MOteQB7e3uKior0+1Ut3gSQnJyMl5cXbdu2BaBjx44kJyfTr1+/R8YgiV4IIYxkTIv+v7toHsXNzY2DBw/i5eXF1atXady46ikr/vCHP7B7924AioqKOH/+PB07dnxs3ZLohRDCSNpS09fZp08fIiMjiYiI4PTp0wQEBLB9+3bq16/PW2+9pS/Xt29fjh07hp+fH7/99hu+vr761v2jSKIXQghj6Ux/UVmpVLJp0ybi4uIYOnQoPXv2rLKcQqHgo48+MqpuSfRCCGEkY7pujKFSqRgyZIjJ65VEL4QQRtJp69Yw0VpN9DqdznLG1Qohnhs11aKvKbV6Z+z8+fM5fvy4fr+0tJSLFy+yefNmrly5UouRCSHEo2nLFAZv5qBGWvR+fn4kJiZWOt6jRw+2bNkClLfmT5w4waRJk3j77bdp2bIld+7cQaVSMWjQIO7fv18ToQkhxFOTrhvKrwovWrSoQrdMcXExe/bs0e8nJCTg6OiIvb09DRs25Msvv+TYsWMkJiZWWkNWCCHMifktwPp4NZLo582bV+VdXXPmzNF/vXr1ahQKRYUPA1tbW4qLi2siJCGEMJnnukWflJREREQEBQUFODk5kZOTg62tLba2tvoyarWaAQMG0Lp1azIzMwFIS0sjMDCQ4uJiMjIySElJoaioiI0bN2JnZ2fKEIUQ4qk914ne1dWVzz//nJCQEDw9PTl69CgDBgxAo9GgVJbPZujp6YlKpSIvL4+5c+cC0LVrV7766ivu37/PuHHjiI6ONmVYQghhUnWt66ZGRt04ODjg7OxMs2bNcHR05ODBgzg7O7Nnzx7s7Oywt7evcu4HhUJBaWkpJSUlNRGWEEKYhLbMyuDNHNRIFKmpqaxatYqEhAQaNWpEjx490Gg0dOjQARsbm0rldTod4eHhHD16FFdXV+Lj48nNzZWRN0IIs1QTC4/UJJMm+vv37xMfH0+zZs1wcXGhTZs27Nu3jzFjxjB16lQ6d+6sL6vVatHpdGRlZXH27Fl0Oh0FBQWMHj2ayMhItm/frh+KKYQQ5kSrUxi8mQOTJnqVSoWjoyPLly9n1qxZ/M///A89evRg4cKFfPPNN9ja2jJ79mw0Go1+a9asGRs2bODDDz/k+++/p3HjxgQFBfHDDz8wbNgwU4YnhBAmodMpDN7MgUJnyMqydUBJ9uXaDkGWEnyYmSwl6OU+ubZDMJulBGNnvVjbIdDx48O1HQIAt/LOP9Xj0zq/aXDZrhf2P9W5TEEmNRNCCCOZy9QGhpJEL4QQRjKXvndDSaIXQggjmUvfu6Ek0QshhJHq2pVNSfRCCGEk6boRQggLJ103Qghh4cqe50nNapNPj2m1HQJ2inq1HQIAdora/7FeL6s8TXVt+NfZv9d2CGZj4iuzajsEsgvzazsEk5AWvRBCWDjpoxdCCAtXxwbdSKIXQghjSYteCCEsnPTRCyGEhStDEr0QQlg0bR3rpJdEL4QQRtJKi14IISybro4l+idaYSo9PR1/f3+SkpL485//TFlZ5QU3zp07R3Bw8FMHKIQQ5kZrxGYOnqhFb2trS0lJCa6urhw+fJj4+HjeeOMNysrKUCrLVxbq0qULd+7cITs7m2bNmgHl68QCWFlZ6ctUpWXLlsTHxz9JaEIIUeMs8mJsTEwMsbGxNGjQAACdTselS5fw9/dHq9USFxeHu7s7QUFB2NnZUVpairW1Nfb29oSFhen38/LyiIiIwNXVFQB3d3e8vLwqne/wYfNYbkwIIapiLi11QxmU6NVqNWPHjmXkyJH6YyNGjGDLli2kpaXRqFEjGjduzM6dO7l06RIffPABX3/9NU5OThQUFDBq1CimTZvG0KFDAYiNjWX//v20aNGC06dPVzqfnZ0d48aNY9asWXTr1s1ET1UIIUyjrvXRG5ToFQoFkZGRfP311wCsX78eGxsbNBoNq1atwsvLi2HDhvHtt9+yYMECQkNDadKkCQD29vYEBQWxZs0akpKS+PDDD/Hx8WH48OFs27at6qCsrXn33XdN9BSFEMK0amryyjVr1nDgwAGaNGnCokWL9N3ej7Js2TJUKhVTp059bDmDLsaWlJQQFhbGzp07sbKyws7Ojnbt2vHPf/6T3Nxchg0bBsC1a9eIiooiMTGR3bt3A3DmzBliYmL46quv8PHxqVBnTEwMLVu2pGXLlnzzzTf6rzds2GBIWEIIUSu0KAzeDHXmzBni4uKIjY1l/PjxrFq16rHlz549q298V8egFn1eXh4vvfQSUH5BVaVS0bt3byIiIli/fr2+3MSJEwEIDg4mMDCQ3r17Ex4ezuLFi3F0dMTR0bFCvVlZWURHRwNw+/Zt/deFhYUGBS+EELXBmPul8vPzyc+vPD2zg4MDDg4O+v2EhAS8vLxQKpX07t2b+fPnP7LOoqIiPvvsMyZMmFDlqMf/ZlCiT0lJYeTIkaSkpFBSUgLA+fPnsbW1pUuXLpw4cYLWrVvTrl07AFq1aoWfnx/Dhg1j7ty5VY6u0el0+Pn54eTkBEBmZiYDBw4E4M6dO2i1Wv3oHCGEMCelCsNb6tHR0URGRlY6PmXKlApdLmq1Wn9NUqFQPLbBu2TJEgIDA9FoNNy4caPaGKpN9Onp6eTm5tKqVStmzpyJr68vM2bMoGnTpoSEhDB9+nRsbGzw9PSkXbt23Lp1ix07dnD8+HHCwsKIjo7m7t27DB48mM6dO6P4vxfo5MmTnD17lnr1yhfryMvL49ChQwCUlpZy/fp1XnzxxWqfgBBCPGvGtOjHjh2Lt7d3peMPt+ah/HpmUVGRfr+goOrFe3788Ud+++03vLy82Llzp0ExVJvok5OTmTx5Mo0bN2b9+vWEhITQv39/vL290el0ZGZmcujQIdzd3fH09KRp06Z4e3vz9ddfo1QqGTVqFFu2bGHOnDmkp6ezf/9+cnNziY6OrtCV06BBA/3wTYCPP/6Y5cuX07x5c4OeiBBCPCvGDK/87y6aR3Fzc+PgwYN4eXlx9epVGjduXGW5gwcPkp6eTkBAAFlZWWg0Glq0aIGfn98j61bodDqTTc+Tk5OjH21TlcLCwgrJ3JRGtKs8Hv9Zk6UEfydLCZofc1hKMCbzRG2HAECppvrujsfZ0nq0wWX9MzcbVK6srIzRo0fj4uLC6dOn8fHxQaVSUb9+fd56660qH7Nz505u3LhR7agbk2aExyV5oMaSvBBCPEs1MamZUqlk06ZNxMXFMXToUHr27FntYx6+t+lxar/pJ4QQdUxNzVKsUqkYMmSIyeuVRC+EEEYqrVs3xkqiF0IIY9WxdUck0QshhLFqagqEmiKJXgghjGSRs1cKIYT4nST6WlJPUfvTJSjNZOpSazOIQ2nELeLi2VCYwfvCUpTVsZfSYhK9EEI8K9KiF0IICyejboQQwsLJqBshhLBw0nUjhBAWThK9EEJYOBl1I4QQFk5a9EIIYeHq2qibJ7rLKD09HX9/f5KSkvjzn/9c5eK0586dIzg4+LH1XLlyhfj4eKB80fEH69FC+XKCWm1d+9wUQjwPtOgM3szBE7XobW1tKSkpwdXVlcOHDxMfH88bb7xBWVkZSqUSgC5dunDnzh2ys7Np1qwZgD5xJycns2LFCu7du0d6ejrdunXjj3/8I8nJyWRlZaFQKGjevDmzZ8+me/fuJnqqQghhGnWtCWpQoo+JiSE2Nla/QpROp+PSpUv4+/uj1WqJi4vD3d2doKAg7OzsKC0txdraGnt7e8LCwvT7eXl5REREkJeXR8+ePVEoFAQGBpKZmUlaWhozZsxg0aJFeHp64u7urv/QEEIIc2Ie7XTDGZTo1Wo1Y8eOrbBs1YgRI9iyZQtpaWk0atSIxo0bs3PnTi5dusQHH3zA119/jZOTEwUFBYwaNYpp06YxdOhQoLxln5SUxD/+8Q9OnDhBw4YN+eSTTxgyZAiDBw/m0KFDLF68mG3bttXMsxZCiKdQ1xYeMaiPXqFQEBkZyciRIxk5ciS5ubnY2Nig0WhYtWoVp0+fBuDbb78lKCiIyZMn69ePtbe3JygoiDVr1rBw4UIATp06xc2bNxk0aBCtW7cmICAAlUpFp06d6NixI3379pX1ZYUQZquu9dEblOhLSkoICwtj586dWFlZYWdnR7t27fjnP/9Jbm4uw4YNA+DatWtERUWRmJjI7t27AThz5gwxMTF89dVX+Pj4ANCrVy/eeecdMjMzcXR0JCoqiuTkZAAuXrxYA09TCCFMR2fEZg4M6rrJy8vjpZdeAsq7XVQqFb179yYiIoL169fry02cOBGA4OBgAgMD6d27N+Hh4SxevBhHR0ccHR0B2Lt3L5999hmtW7emqKgIBwcH2rRpA0B2djbt27dHpzOXl0gIISqqaxdjDWrRp6Sk4OTkREpKin4I5Pnz57G1taVLly6cOHGC69ev68u3atUKPz8/hg0bhq+vL126dKlQn5eXFxMmTCA0NJSYmBj9yBx3d3cyMzMpKChgwIABJnyaQghhOnWt66baFn16ejq5ubm0atWKmTNn4uvry4wZM2jatCkhISFMnz4dGxsbPD09adeuHbdu3WLHjh0cP36csLAwoqOjuXv3LoMHD6Zz584oFAoU/7coxZIlS1i7di0KhQJ7e3uuXbtGUFAQmzZtAqgwXFMIIcxF5TuHzFu1Lfrk5GQmT55M48aNWb9+PadOneK1115j3rx5+Pn50bVrVy5fvoy7uzuenp5Mnz6dFi1a8PXXXzNu3DhiY2OxsbFhzpw5vPLKK9y+fRso7/efNWsWMTEx3L9/n+DgYLp3786gQYP429/+RnFxMXl5eTX9/IUQwmh1rUWv0JmwMzwnJ0c/2qYqhYWFjxxNc//+fWxsbJ743D7thz/xY03F1kxmlLBX1H4c17QFtR0CAP88E1nbIZiN4Fdm13YIbMr8qbZDAKBUc+OpHh/24rsGl11xdetTncsUTJoRHpfkgccOmXyaJC+EEM9SXbsYW/tNPyGEqGN0ZtIlYyhJ9EIIYSRp0QshhIUrkxa9EEJYNnMZTWMoSfRCCGEk6boRQggLJxdjhRDCwtVUi37NmjUcOHCAJk2asGjRIv2iTQ8rLS1l3rx53Lp1C7VazeTJk3njjTceW6/FJPpNs9vVdgjw0FKIzz1l5TdobZj4yqzaDgEF5jF5+epTi2s7BI79cVRth2ASNXEx9syZM8TFxREbG8vJkydZtWoV4eHhlcrFx8fTtWtXFi9ezK+//srs2bOfn0QvhBDPitaICQXy8/PJz8+vdNzBwQEHBwf9fkJCAl5eXiiVSnr37s38+fOrrG/gwIH6r3NycmjRokW1MUiiF0IIIxnTno+OjiYysvJUHFOmTGHq1Kn6fbVaTbdu3YDyxZ4KCwsfW+/9+/dZsmQJn376abUxSKIXQggjGTO8cuzYsXh7e1c6/nBrHspX4ysqKtLvFxQ8fr6ojz/+mJEjR9K9e/dqY5BEL4QQRjJm1M1/d9E8ipubGwcPHsTLy4urV6/SuHHjR5ZdsGABTZs25f333zcoBoMWHhFCCPE7rRGbofr06cPFixeJiIggLCyMgIAAtm/fzt69eyuUS0hIYNOmTZw9exZ/f3/Gjh1bbd3SohdCCCOV1cAAS6VSyaZNm4iLi2Po0KH07NmzynKvvvoq58+fN6puSfRCCGGkmhpHr1KpGDJkiMnrNXnXTU5ODuvWratwLC8vj3PnzrFhwwZycnL0x3fv3s0XX3yh3582bRqXL182dUhCCGFSOp3O4M0cGNyi9/PzIzExsdLxHj16sGXLFi5dukRoaCj169fn2rVrHDhwAGdnZ9q3b09xcTEDBw6kX79+qFQq/WP37t3L9OnTATh9+jRXrlxh48aNVd4kIIQQ5sJiJzVTKBQsWrRIv7A3QHFxMXv27AGgU6dOfPLJJ0B58v/4448JDw9n/fr1dOzYkZdffrlCfampqWRmZvLSSy9RUFDAokWLWLt2LbGxsSxfvpywsLAK5xJCCHNhsZOazZs3r8pxnXPmzAFAq9Vib2/P8ePHqVevHtbW1pSVlWFlZUVSUhLW1tbodDpefPFFunXrxoIFC7C1teX27dvMnDmTyZMn07JlS6ZMmcLChQsJCAjg008/pVOnTqZ7tkIIYQIWN6lZUlISERERFBQU4OTkRE5ODra2ttja2urLqNVq+vXrR1xcHABRUVF06NCBwMBA+vfvj1qtJiEhgdu3bzNx4kR2795N+/btuXTpEvHx8UyZMoVdu3bRr18/Ll68SIMGDQgMDKRp06Y198yFEOIJlenqVpu+2kTv6urK559/TkhICJ6enhw9epQBAwag0WhQKpUAeHp60qhRI4KDg7l37x7Tp09n48aNlJSUsG7dOv70pz+h0+k4f/48Hh4elJWVMWTIEIKCgvD19QVgxYoVAGg0GjIyMpg2bVoNPm0hhHhydSvNGzHqxsHBAWdnZ5o1a4ajoyMHDx7E2dmZPXv2YGdnx4ULF/Dz82P8+PEkJyczatQowsLCyMrKqnSHl1KppEGDBvp9jUZDw4YNgfJrAVZWch+XEMJ86Yz4Zw4MzqipqamsWrWKhIQEGjVqRI8ePdBoNHTo0AEbGxu6du3K66+/zvvvv0/37t1xc3MjPDycf//733Tp0uWxdaekpNCunRlMMyyEEAbQojN4MwfVJvr79+8THx9Ps2bNcHFxoU2bNuzbt48xY8YwdepUOnfuDEBcXBzXr1+nb9++APTv35/du3ejUCiws7Orsu6ysjI0Gg3Lli1j+PDhJnxaQghRcyxuHL1KpcLR0ZHly5fToUMHIiMjadeuHQsXLuSbb74hMTGR2bNnExERgYeHByEhIbz66qu89tprJCQkMGbMGKD8A0Oj0VSou7CwkK1bt/L//t//w9XV9ZHlhBDCnNTEFAg1SaEzl4+cp1T49ym1HYKsMPWw/7tQX9smL7td2yHIClMP6WYmK0z9J+v0Uz2+b5uB1Rf6P0dvHHqqc5mCzHUjhBBGqmutY0n0QghhJHO5yGooSfRCCGEkSfRCCGHh6tqlTUn0QghhpLo26kYSvRBCGEla9EIIYeGkj14IISyctOhrifNHh2s7BEq1ZbUdgtkwl0VjsgvzazsEs3HMDG5WSj2/vbZDMAlp0QshhIUzl1kpDSWJXgghjGRxC48IIYSoSCt99EIIYdmk60YIISyctOiFEMLCSYteCCEsXF27GFvtUoIajYbIyEj91w9s376dlJQUg07yxRdfUFZWeYz5lStXiI+PB0Cr1VLy0MIdpaWlaLV168UUQjwfdDqtwZs5qLZFX1xczNmzZ1m7di1Hjx7lt99+o3fv3tja2tK2bVsSExM5cuQIoaGhBAYGotVqKS4uxsPDg65du9KpUyeOHj3KpEmT9HUmJSWxYsUK7t27R3p6Ot26deOPf/wjycnJZGVloVAoaN68ObNnz6Z79+41+gIIIYSxLO6GKXt7e9avX09+fj4TJkwgMTGR7777Dii/+3HDhg1MnDgRgHr16hEZGcnly5f5/vvvOXz4ML/88gtZWVmsXLkShUJBSEgIeXl59OzZE4VCQWBgIJmZmaSlpTFjxgwWLVqEp6cn7u7uKM1kOTohhHhYXZsCodqum127dhEcHExRURF+fn4sXLiQli1bAnD9+nXq16+Pi4sLUJ7ox4wZw7x589DpdFy4cIG//vWvtGnThtDQUEJCQgB4/fXX0el0bN26lQ8++IAVK1bQq1cvhgwZgrW1NYcOHcLf378Gn7YQQjw5LTqDN3NQbYv+nXfewd7eXt+HvmPHDs6cOcOSJUvIyMigZcuWLF26FG9vbyZNmsSFCxdQKpUMHToUNzc37t69S1FRETk5OWi1Who0aEBKSgo3b95k0KBBFBYW8vbbb6NSqejUqRMdO3bkhRde4Pz588/i+QshhNEsrkUP8Nprr9G8eXOysrJ47733uHXrFj169GDo0KGcPn2a8ePH07ZtWyIiIgD4/PPPCQ8P58CBAyxevJhz587x8ccfs2zZMpKSkujVqxfvvPMOmZmZODo6EhUVRXJyMgAXL16suWcrhBAmUKbTGrwZY82aNXh7exMUFER2dvYjy+3evZu3336bgIAALl++XG29Bg2v/Ne//oVCoeDYsWNs376d4uJi6tWrR8OGDbG2tsbKygqVSkX9+vUBmDp1KiNGjADg7NmzpKam8tprr+m7Y/bu3ctnn31G69atKSoqwsHBgTZt2gCQnZ1N+/bt69wnphDi+VET+enMmTPExcURGxvLyZMnWbVqFeHh4ZXKpaens3r1anbs2MGdO3eIiIhg3bp1j63boBZ9XFwc/fr10+8/mIK2sLCQl19+mR07dlQof/v2bf2wyc2bN/PRRx9x5MgR7t+/D4CXlxcTJkwgNDSUmJgYsrOzadasGe7u7mRmZlJQUMCAAQMMCU0IIZ45Y/ro8/PzycjIqLTl51ecQjshIQEvLy+USiW9e/cmMTGxynP/8ssv9O/fnwYNGvDiiy+SlZVV5fD1h1Xbor958yaFhYU4OTmRnZ3N1atXcXZ2pri4mE8//ZQPP/yQpUuXYmVlRWJiInl5ebi4uNCxY0c2b96MVqvFw8ODu3fvMmPGDJYsWYKtrS0AS5YsYe3atSgUCuzt7bl27RpBQUFs2rQJgLKyMhl5I4QwO8a06KOjo/X3Ij1sypQpTJ06Vb+vVqvp1q0bUN6YLiwsrLI+tVpNq1at9Pu2trbk5OTQvHnzR8ZQbaK/ceMG77zzDgAnT57kypUrvP/++1y7do2lS5fyyiuv4ODggI2NDXv37qVt27YAbNiwgaSkJBYuXAjAm2++SXJyMkeOHGHo0KGUlJQwa9Ys+vbti7e3N8HBwQwcOJBBgwbxxhtvMHv2bPLy8mjatGl1IQohxDNlzFw3Y8eOxdvbu9JxBweHCvv29vYUFRXp9wsKCqqsz97enjt37uj31Wp1tR88Cl0NdYaXlJRQr149g8vfv38fGxubJz5fm8YvPfFjTUVWmPqdrDBlfjo4tqztEMxmhal6zTo+1eMb2//B4LK5BYYNMDl+/DgHDx4kIiKCq1ev8sEHH3Dw4MFK5a5cuUJ4eDgbNmygoKCAgQMHkpCQgLX1o9vtNZbonzVJ9OZFEr35kUT/u6dN9A52hj8+X139qBgo76oePXo0Li4unD59Gh8fH/0gl7feeqtC2WnTpmFnZ0dGRgbdu3dn9uzZj61bEr0JSaL/nSR68yOJ/ndPm+jtG3QwuGxB4RWDy2o0GuLi4mjevDk9e/Z8ZDmtVkt8fDzW1ta8/vrr1dYrs1cKIYSRamqaYpVKxZAhQ6otZ2VlZdTIREn0QghhJFl4RAghLFxd6/GWRC+EEEbSmsk884aSRC+EEEaSFr0QQli4upXmLWh4pRBCiKoZNKmZEEKIuksSvRBCWDhJ9EIIYeEk0QshhIWTRC+EEBZOEr0QQlg4SfRCCGHhJNELIYSFk0T/CM/iPjK1Wl3rMRjq3r17tXZuc3odxNPTaDT6NVQ1Go3++Pbt20lJSTGoji+++KLKBbGvXLlCfHw8UD5ne0lJif57paWlaLV1a44aU3kuEr1Go6G0tLTK75WVlVV4sz0wc+ZMDh8+bPJYHqwUU1JSwsCBA7l79+4jy9ZUDNXRaDTk5OSQn59Pfn4+v/76K4MGDeK3337TH8vJyanydasJ8+fP5/jx4/r90tJSLl68yObNm7lyxfBFHR5IT0/H39+fpKQk/vznP1eZMM6dO0dwcPBTxf2s4qjJ5JaTk8O6desqHMvLy+PcuXNs2LCBnJwc/fHdu3fzxRdf6PenTZvG5cuVV1cqLi7m7NmzrF27lqCgIIYPH878+fPJyMigoKCAxMREVq5cCUBgYCBjxozB19eXZcuWsW/fPtLS0jh69ChKpVJfZ1JSEoGBgcycOZNZs2YRGBjIkiVLGDduHJ6engwZMoRx48bx73//+4lfi7rsuZjrZuXKlfz0008UFxeTk5ND+/btKSoq4tatW7Rt2xYnJyeioqKA8hXbo6OjcXR05IsvviAqKoqysjJatGihL2Osmzdvkp6eTq9evbC3twfg2LFjvPrqqxUWP9fpdCgUihqJ4WF+fn4kJiZWOt6jRw+2bNnC1atXWbt2bYVfpAEDBrBgwQL9vlarZfz48XTu3LnG4oDy1+TEiRNMmjSJt99+m5YtW3Lnzh1UKhWDBg3i/v37Rp/X1taWkpISXF1dOXz4MPHx8bzxxhuUlZXpn3OXLl24c+cO2dnZNGvWTP+coXzRhwdlqtKyZUt94q3JOJKTk1mxYgX37t0jPT2dbt268cc//pHk5GSysrJQKBQ0b96c2bNn07179wrnru61v3TpEqGhodSvX59r165x4MABnJ2dad++PcXFxQwcOJB+/fqhUqn0j927dy/Tp08H4PTp01y5coWNGzcSHh5e4Rz29vasX7+e/Px8JkyYQGJiIt999x1QvjLZhg0bmDhxIgD16tUjMjKSy5cv8/3333P48GF++eUXsrKyWLlyJQqFgpCQEPLy8ujZsycKhYLAwEAyMzNJS0tjxowZLFq0CE9PT9zd3Su8p58nz0Wif7Ce4s8//8zWrVtZsWIFycnJREZGsnr16gpllUolPj4+BAQEEBYWRlhYGK1ateKjjz564vNfvXqV77//nl69eumPbdu2jbt37+Lv78/ly5dp06YNPj4+vPfeezUSw8MUCgWLFi2qsNxfcXExe/bsAaBz584sWbKEmJgYDh06VOnxfn5+DB06tMbjAEhISMDR0RF7e3saNmzIl19+ybFjx0hMTGT8+PEGnScmJobY2FgaNGgAlH94XLp0CX9/f7RaLXFxcbi7uxMUFISdnR2lpaVYW1tjb29PWFiYfj8vL4+IiAhcXV0BcHd3x8vLq9L5HvVXmKnjeJrkVt1r36lTJz755BOgPPl//PHHhIeHs379ejp27MjLL79cob7U1FQyMzN56aWXKCgoYNGiRaxdu5bY2FiWL19OWFiY/ly7du3iu+++429/+xsTJkxAoVDw5ptvcvfuXa5fv079+vVxcXEByhP9mDFj0Gg09O/fnwsXLrBnzx7GjBlDaGio/vyvv/46SUlJ/OMf/+DEiRM0bNiQTz75hCFDhjB48GAOHTrE4sWL2bZtW/VvGAv0XCR6Q5w7d46//vWv5OXlUVZWxpEjRygtLeUvf/kLOp2OjIwMfHx8mDFjBn369DGqbisrqwq/bBcuXCAtLY21a9fi7OyMj48P27ZtIyUlhZEjR9ZIDA+bN28eBQUFlY7PmTOnwn56ejqDBw+u8EudkJBAVlbWE5/b2DhWr16NQqGokJBsbW0pLi42+DxqtZqxY8cycuRI/bERI0awZcsW0tLSaNSoEY0bN2bnzp1cunSJDz74gK+//honJycKCgoYNWoU06ZN03+4xcbGsn//flq0aMHp06crnc/Ozo5x48Yxa9YsunXrVmNxaLXaJ05u1b32Wq0We3t7jh8/Tr169bC2tqasrAwrKyuSkpKwtrZGp9Px4osv0q1bNxYsWICtrS23b99m5syZTJ48mZYtWzJlyhQWLlxIQEAAn376KZ06deKdd97B3t5e3820Y8cOzpw5w5IlS8jIyKBly5YsXboUb29vJk2axIULF1AqlQwdOhQ3Nzfu3r1LUVEROTk5aLVaGjRoQEpKCjdv3mTQoEEUFhby9ttvo1Kp6NSpEx07duSFF17g/PnzBr9nLI3FJ/p9+/axbt06rK2tUavV3L17F19fX33Xja+vLyUlJYSEhLBt2zamTp1KcHAwN2/e5MaNG/j6+pKbm8vKlStZunSpSWLauHEjfn5+REdHEx4ejlarxcrKChcXlxqNISkpiYiICAoKCnByciInJwdbW1tsbW31ZdRqNUuXLqV9+/b07duX1NRUfvrpJ/33rayscHNze5qnb3AcAwYMoHXr1mRmZgKQlpZGYGAgxcXFZGRkkJKSQlFRERs3bsTOzu6R51MoFERGRvL1118DsH79emxsbNBoNKxatQovLy+GDRvGt99+y4IFCwgNDaVJkyZAeTdDUFAQa9asISkpiQ8//BAfHx+GDx/+yNahtbU17777bo3HcerUKaOTm6Gvfb9+/YiLiwMgKiqKDh06EBgYSP/+/VGr1SQkJHD79m0mTpzI7t27ad++PZcuXSI+Pp4pU6awa9cu+vXrx8WLF2nQoAGBgYEVuilfe+01bGxsyMrK4r333uP999+nR48e9OjRg3Xr1vHll1/SoEEDff/8559/zqlTpygpKWH//v2cO3eOjz/+GAcHB4YPH06fPn2wsrJizZo1tG/fnqioKP1ffBcvXuSFF1545PvjeWDxib5fv3706dMHBwcH9u7dy4ULF5gzZ46+6+bLL79ErVajUqmIi4tDo9Hg5uaGm5sbP/zwA2q1mokTJzJ69GiT9e+Fh4ej0+kYOXIkaWlpODs7A+VJ9IcffqixGFxdXfn8888JCQnB09OTo0ePMmDAADQajb5eT09PmjRpwrvvvkv9+vWrrOfHH38kLy+PrVu3PrKMKeJQqVTk5eUxd+5cALp27cpXX33F/fv3GTduHNHR0Qadr6SkhLCwMN566y18fHyws7OjXbt2/POf/yQ3N5dhw4YBcO3aNaKiovjHP/5BSUkJo0aN4syZM8TExLBp06YKf8mUlJQQExPDrFmzAFi+fLm+f3rx4sVVJnpTx9GrVy+jk5uhr32jRo0IDg7m3r17TJ8+nY0bN1JSUsK6dev405/+hE6n4/z583h4eFBWVsaQIUMICgrC19cXgBUrVgDlF/YzMjKYNm1ahTj+9a9/oVAoOHbsGNu3b6e4uJh69erRsGFDrK2tsbKyQqVS6d9fU6dOZcSIEQCcPXuW1NRUXnvtNfz9/YHy6wOfffYZrVu3pqioCAcHB9q0aQNAdnY27du3f65Hb1l8on9w8RMgPj6+Ut+yQqHQl7G1tSU/P1//5nmgSZMmHDhwgC5duuDh4WF0DL/++iuHDh3i+vXraDQarK3LX3ZXV1fmzp1LSEiIvmxNxfAwBwcHnJ2dSU1NxdHRkZiYGEJDQ1m2bJm+W6GwsJCtW7fyyy+/cPXqVf1jnZyc6Nu3LyNHjnzqD77q4rCxsalyxIhCoaC0tJSSkhLq1atX7Xny8vJ46aWXgPIuCZVKRe/evYmIiGD9+vX6cg8uAAYHBxMYGEjv3r0JDw9n8eLFODo64ujoWKHerKws/YfN7du39V8XFhY+kzieJrlV99pfuHCBefPmAeUfPKNGjcLJyYkWLVrQu3fvCqNtlEql/roDlCf3hg0bAuU/qwcXrx8WFxfH3/72N/3+g665wsJCXn75ZXbs2MG4ceP03799+zbx8fH069ePzZs389FHH7Fhwwb9+8TLy4s7d+7g7OxM37598fPzo1mzZri7uxMfH09BQQEDBgyo8rV4HjwXwyuh/M/+U6dO0bdv30eWuXfvHh4eHmzZsgUbG5sK/7u4uFQ77v1RBgwYwOrVq1m9enWFUQp/+MMfuHLlCq+88kqNx/Cw1NRUVq1aRUJCAo0aNaJHjx5oNBo6dOiAjY0N8Psv3v79+2nVqhWurq506NCBb775Rl/Pw/3mNRXHw3Q6HeHh4Rw9ehRXV1fi4+PJzc2tduRNSkoKTk5OpKSk6Icenj9/HltbW7p06cKJEye4fv26vnyrVq3w8/Nj2LBh+Pr6Vjm6RqfT4efnx8CBAxk4cCCNGjXSfz18+PAqP6BMHYeXlxcTJkwgNDSUmJgY/cgcd3d3MjMzH5vcqnvtu3btyuuvv877779P9+7dcXNzIzw8nH//+9+PHG308PNs167dI79/8+ZNCgsLcXJyIjs7m6tXr2JlZUVxcTGffvopL7/8Mps3byY6OprExEQ2bdrE9evXKSkpYfPmzWi1Wjw8PBgxYgQzZsygqKhI/15csmQJAQEB+gbctWvXCAoKYtOmTVy8eLHKIazPA4tv0UN5i3rSpEnMmzdP3xep1WortXaqank87EkTW9u2bfVf63Q6ysrKiImJYdeuXcydO5fx48cTFhaGh4dHjcUAcP/+feLj42nWrJl+VMO+ffuYNm0anp6eTJ06tUKcAG3atKkwMunBhdmn+TPYmDge/JyysrI4e/YsnTt3pqCggNGjRxMaGsqbb76JSqUiMDCwynOlp6eTm5tLq1atmDlzJr6+vsyYMYOmTZsSEhLC9OnTsbGxwdPTk3bt2nHr1i127NjB8ePHCQsLIzo6mrt37zJ48GA6d+6sf/1PnjzJ2bNn9X9R5OXl6UcolZaWcv36dV588cUajePh5LZ27doqkxtQYbimoa99XFwc169fJyAggD179tC/f392796NQqF45PWQB/ekLFu2TD/SrSo3btzgnXfe0b+OV65c4f333+fatWssXbqUV155BQcHB2xsbNi7d6/+92fDhg0kJSWxcOFCAN58802Sk5M5cuQIQ4cOpaSkhFmzZtG3b1+8vb0JDg5m4MCBDBo0iDfeeIPZs2eTl5dX4VrB88LilxIsLS1l5syZeHh4VOgOOXXqFFFRUfo/mZctW8aRI0fQaDS0atWKS5cu0alTJ/3/GRkZ2NjYMGDAAGbOnPnE8QwfPhxnZ2fq1avHRx99hL29PYmJiURERKBUKiksLKyxGHQ6Hd9++y3Ozs506NCByMhI2rVrx/Hjx/XjmU+fPk1ERARvv/02+/fvr7KeJUuW8NNPP7Fz584neg2MiSMvL48pU6awefNmzpw5g7u7O2FhYcyfP5+jR48SExPD3//+d5o3b17lufbv309paSnDhw8HICQkhP79++Pt7Y1Op2PFihUcOnSINWvW8L//+780bdoUb29vfddUQUEBW7ZsYd++faSnp7N//35yc3NZsGBBhesTqampFUbYFBYWsnz5cn1cNRGHk5MTX375Jd26ddMntyZNmjBw4EDee+89tFots2fPZu7cufrkZsxr/2CQgoeHBxMmTGDRokW4uLgwbNgw/Y1LM2bM0D9nLy8vfH19uXfvHpMnTwbQt8iXL1/+RO+VhxnaVffA/fv3q/zL8Hlk8YneHD0YD11XGfsLV1fk5OToR7lUpbCwsEJftDnGIclNVEUSvRBCWLjn5mKsEEI8ryTRCyGEhZNEL4QQFk4SvRBCWDhJ9EIIYeH+PzBPshJJCiUrAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<Figure size 432x288 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "sns.heatmap(df.corr())\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "c94543c3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.44444275 0.44444275 0.40350723 ... 0.07797702 0.7880707  0.6       ]\n",
      " [0.4259262  0.37037277 0.45614243 ... 0.331144   0.7019806  0.6       ]\n",
      " [0.35185242 0.4259262  0.40350723 ... 0.2190837  0.63575745 0.40000004]\n",
      " ...\n",
      " [0.9259262  0.90740967 0.85964966 ... 0.16001847 0.98013306 0.40000004]\n",
      " [0.90740967 0.8888893  0.84210587 ... 0.196412   0.9867554  0.20000002]\n",
      " [0.90740967 0.9259262  0.87719345 ... 0.32232267 1.         0.40000004]]\n"
     ]
    }
   ],
   "source": [
    "#获取DataFrame中的数据，形式为数组array形式\n",
    "values=df.values\n",
    "#确保所有数据为float类型\n",
    "values=values.astype('float32')\n",
    " \n",
    "# 特征的归一化处理\n",
    "scaler = MinMaxScaler(feature_range=(0, 1))\n",
    "scaled = scaler.fit_transform(values)\n",
    "print(scaled)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "bee1cd05",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义series_to_supervised()函数\n",
    "# 将时间序列转换为监督学习问题\n",
    "def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):\n",
    "    \"\"\"\n",
    "    将时间序列框定为有监督的学习数据集。\n",
    "        论据：\n",
    "        数据：作为列表或NumPy数组的观察序列。\n",
    "        n_in：作为输入的滞后观测数（X）。\n",
    "        n_out：作为输出的观察数（y）。\n",
    "        dropnan：布尔值，决定是否删除具有NaN值的行。\n",
    "    返回：\n",
    "    pd.DataFrame(用于监督学习)\n",
    "    \"\"\"\n",
    "    n_vars = 1 if type(data) is list else data.shape[1]\n",
    "    df = pd.DataFrame(data)\n",
    "    cols, names = list(), list()\n",
    "    # input sequence (t-n, ... t-1)\n",
    "    for i in range(n_in, 0, -1):\n",
    "        cols.append(df.shift(i))\n",
    "        names += [('var%d(t-%d)' % (j + 1, i)) for j in range(n_vars)]\n",
    "    # forecast sequence (t, t+1, ... t+n)\n",
    "    for i in range(0, n_out):\n",
    "        cols.append(df.shift(-i))\n",
    "        if i == 0:\n",
    "            names += [('var%d(t)' % (j + 1)) for j in range(n_vars)]\n",
    "        else:\n",
    "            names += [('var%d(t+%d)' % (j + 1, i)) for j in range(n_vars)]\n",
    "    # put it all together\n",
    "    agg = pd.concat(cols, axis=1)\n",
    "    agg.columns = names\n",
    "    # drop rows with NaN values\n",
    "    if dropnan:\n",
    "        agg.dropna(inplace=True)\n",
    "    return agg"
   ]
  },
  {
   "cell_type": "raw",
   "id": "f331b2f2",
   "metadata": {},
   "source": [
    "该函数有四个参数：\n",
    "\n",
    "    data：输入数据需要是列表或二维的NumPy数组的观察序列。\n",
    "    n_in：输入的滞后观察数（X）。值可以在[1..len（data）]之间，可选的。默认为1。\n",
    "    n_out：输出的观察数（y）。值可以在[0..len（data）-1]之间，可选的。默认为1。\n",
    "    dropnan：Bool值，是否删除具有NaN值的行，可选的。默认为True。\n",
    "\n",
    "该函数返回一个值：\n",
    "\n",
    "    返回：用于监督学习的Pandas DataFrame。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "6ef2ef1e",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "#将时间序列转换为监督学习问题\n",
    "reframed = series_to_supervised(scaled, 1, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "76bad08c",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>var1(t-1)</th>\n",
       "      <th>var2(t-1)</th>\n",
       "      <th>var3(t-1)</th>\n",
       "      <th>var4(t-1)</th>\n",
       "      <th>var5(t-1)</th>\n",
       "      <th>var6(t-1)</th>\n",
       "      <th>var7(t-1)</th>\n",
       "      <th>var8(t-1)</th>\n",
       "      <th>var1(t)</th>\n",
       "      <th>var2(t)</th>\n",
       "      <th>var3(t)</th>\n",
       "      <th>var4(t)</th>\n",
       "      <th>var5(t)</th>\n",
       "      <th>var6(t)</th>\n",
       "      <th>var7(t)</th>\n",
       "      <th>var8(t)</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0.444443</td>\n",
       "      <td>0.444443</td>\n",
       "      <td>0.403507</td>\n",
       "      <td>0.471695</td>\n",
       "      <td>0.078942</td>\n",
       "      <td>0.077977</td>\n",
       "      <td>0.788071</td>\n",
       "      <td>0.6</td>\n",
       "      <td>0.425926</td>\n",
       "      <td>0.370373</td>\n",
       "      <td>0.456142</td>\n",
       "      <td>0.358490</td>\n",
       "      <td>0.335752</td>\n",
       "      <td>0.331144</td>\n",
       "      <td>0.701981</td>\n",
       "      <td>0.6</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0.425926</td>\n",
       "      <td>0.370373</td>\n",
       "      <td>0.456142</td>\n",
       "      <td>0.358490</td>\n",
       "      <td>0.335752</td>\n",
       "      <td>0.331144</td>\n",
       "      <td>0.701981</td>\n",
       "      <td>0.6</td>\n",
       "      <td>0.351852</td>\n",
       "      <td>0.425926</td>\n",
       "      <td>0.403507</td>\n",
       "      <td>0.377357</td>\n",
       "      <td>0.222373</td>\n",
       "      <td>0.219084</td>\n",
       "      <td>0.635757</td>\n",
       "      <td>0.4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0.351852</td>\n",
       "      <td>0.425926</td>\n",
       "      <td>0.403507</td>\n",
       "      <td>0.377357</td>\n",
       "      <td>0.222373</td>\n",
       "      <td>0.219084</td>\n",
       "      <td>0.635757</td>\n",
       "      <td>0.4</td>\n",
       "      <td>0.425926</td>\n",
       "      <td>0.574074</td>\n",
       "      <td>0.561401</td>\n",
       "      <td>0.452827</td>\n",
       "      <td>0.133182</td>\n",
       "      <td>0.131883</td>\n",
       "      <td>0.728470</td>\n",
       "      <td>0.4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0.425926</td>\n",
       "      <td>0.574074</td>\n",
       "      <td>0.561401</td>\n",
       "      <td>0.452827</td>\n",
       "      <td>0.133182</td>\n",
       "      <td>0.131883</td>\n",
       "      <td>0.728470</td>\n",
       "      <td>0.4</td>\n",
       "      <td>0.574074</td>\n",
       "      <td>0.500000</td>\n",
       "      <td>0.526314</td>\n",
       "      <td>0.471695</td>\n",
       "      <td>0.178836</td>\n",
       "      <td>0.176876</td>\n",
       "      <td>0.781464</td>\n",
       "      <td>0.4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>0.574074</td>\n",
       "      <td>0.500000</td>\n",
       "      <td>0.526314</td>\n",
       "      <td>0.471695</td>\n",
       "      <td>0.178836</td>\n",
       "      <td>0.176876</td>\n",
       "      <td>0.781464</td>\n",
       "      <td>0.4</td>\n",
       "      <td>0.500000</td>\n",
       "      <td>0.462963</td>\n",
       "      <td>0.473686</td>\n",
       "      <td>0.452827</td>\n",
       "      <td>0.119788</td>\n",
       "      <td>0.118366</td>\n",
       "      <td>0.794693</td>\n",
       "      <td>0.8</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   var1(t-1)  var2(t-1)  var3(t-1)  var4(t-1)  var5(t-1)  var6(t-1)  \\\n",
       "1   0.444443   0.444443   0.403507   0.471695   0.078942   0.077977   \n",
       "2   0.425926   0.370373   0.456142   0.358490   0.335752   0.331144   \n",
       "3   0.351852   0.425926   0.403507   0.377357   0.222373   0.219084   \n",
       "4   0.425926   0.574074   0.561401   0.452827   0.133182   0.131883   \n",
       "5   0.574074   0.500000   0.526314   0.471695   0.178836   0.176876   \n",
       "\n",
       "   var7(t-1)  var8(t-1)   var1(t)   var2(t)   var3(t)   var4(t)   var5(t)  \\\n",
       "1   0.788071        0.6  0.425926  0.370373  0.456142  0.358490  0.335752   \n",
       "2   0.701981        0.6  0.351852  0.425926  0.403507  0.377357  0.222373   \n",
       "3   0.635757        0.4  0.425926  0.574074  0.561401  0.452827  0.133182   \n",
       "4   0.728470        0.4  0.574074  0.500000  0.526314  0.471695  0.178836   \n",
       "5   0.781464        0.4  0.500000  0.462963  0.473686  0.452827  0.119788   \n",
       "\n",
       "    var6(t)   var7(t)  var8(t)  \n",
       "1  0.331144  0.701981      0.6  \n",
       "2  0.219084  0.635757      0.4  \n",
       "3  0.131883  0.728470      0.4  \n",
       "4  0.176876  0.781464      0.4  \n",
       "5  0.118366  0.794693      0.8  "
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "reframed.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "aaaf7b39",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>var1(t-1)</th>\n",
       "      <th>var2(t-1)</th>\n",
       "      <th>var3(t-1)</th>\n",
       "      <th>var4(t-1)</th>\n",
       "      <th>var5(t-1)</th>\n",
       "      <th>var6(t-1)</th>\n",
       "      <th>var7(t-1)</th>\n",
       "      <th>var8(t-1)</th>\n",
       "      <th>var7(t)</th>\n",
       "      <th>var8(t)</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0.444443</td>\n",
       "      <td>0.444443</td>\n",
       "      <td>0.403507</td>\n",
       "      <td>0.471695</td>\n",
       "      <td>0.078942</td>\n",
       "      <td>0.077977</td>\n",
       "      <td>0.788071</td>\n",
       "      <td>0.6</td>\n",
       "      <td>0.701981</td>\n",
       "      <td>0.6</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0.425926</td>\n",
       "      <td>0.370373</td>\n",
       "      <td>0.456142</td>\n",
       "      <td>0.358490</td>\n",
       "      <td>0.335752</td>\n",
       "      <td>0.331144</td>\n",
       "      <td>0.701981</td>\n",
       "      <td>0.6</td>\n",
       "      <td>0.635757</td>\n",
       "      <td>0.4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0.351852</td>\n",
       "      <td>0.425926</td>\n",
       "      <td>0.403507</td>\n",
       "      <td>0.377357</td>\n",
       "      <td>0.222373</td>\n",
       "      <td>0.219084</td>\n",
       "      <td>0.635757</td>\n",
       "      <td>0.4</td>\n",
       "      <td>0.728470</td>\n",
       "      <td>0.4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0.425926</td>\n",
       "      <td>0.574074</td>\n",
       "      <td>0.561401</td>\n",
       "      <td>0.452827</td>\n",
       "      <td>0.133182</td>\n",
       "      <td>0.131883</td>\n",
       "      <td>0.728470</td>\n",
       "      <td>0.4</td>\n",
       "      <td>0.781464</td>\n",
       "      <td>0.4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>0.574074</td>\n",
       "      <td>0.500000</td>\n",
       "      <td>0.526314</td>\n",
       "      <td>0.471695</td>\n",
       "      <td>0.178836</td>\n",
       "      <td>0.176876</td>\n",
       "      <td>0.781464</td>\n",
       "      <td>0.4</td>\n",
       "      <td>0.794693</td>\n",
       "      <td>0.8</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   var1(t-1)  var2(t-1)  var3(t-1)  var4(t-1)  var5(t-1)  var6(t-1)  \\\n",
       "1   0.444443   0.444443   0.403507   0.471695   0.078942   0.077977   \n",
       "2   0.425926   0.370373   0.456142   0.358490   0.335752   0.331144   \n",
       "3   0.351852   0.425926   0.403507   0.377357   0.222373   0.219084   \n",
       "4   0.425926   0.574074   0.561401   0.452827   0.133182   0.131883   \n",
       "5   0.574074   0.500000   0.526314   0.471695   0.178836   0.176876   \n",
       "\n",
       "   var7(t-1)  var8(t-1)   var7(t)  var8(t)  \n",
       "1   0.788071        0.6  0.701981      0.6  \n",
       "2   0.701981        0.6  0.635757      0.4  \n",
       "3   0.635757        0.4  0.728470      0.4  \n",
       "4   0.728470        0.4  0.781464      0.4  \n",
       "5   0.781464        0.4  0.794693      0.8  "
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 删除不想预测的特征列，这里只预测收盘价\n",
    "# 所以删除的是var1(t),var2(t),var3(t),\n",
    "reframed.drop(['var1(t)','var2(t)','var3(t)','var4(t)','var5(t)','var6(t)'], axis=1, inplace=True)\n",
    "# 打印数据的前5行\n",
    "reframed.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c52b915c",
   "metadata": {},
   "source": [
    "## 数据划分为训练集和测试集：\n",
    "\n",
    "* 将处理后的数据集划分为训练集和测试集。这里按0.85比例划分，将训练集和测试集的最终输入（X）转换为为LSTM的输入格式，即[samples,timesteps,features]。\n",
    "\n",
    "* Keras LSTM层的工作方式是通过接收3维（N，W，F）的数字阵列，其中N是训练序列的数目，W是序列长度，F是每个序列的特征数目。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "1fb4061b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(200, 1, 9) (200,)\n",
      "(36, 1, 9) (36,)\n"
     ]
    }
   ],
   "source": [
    "# 划分训练集和测试集\n",
    "train = reframed.iloc[:int(len(reframed)*0.85),:].values\n",
    "test = reframed.iloc[int(len(reframed)*0.85):,:].values\n",
    "# 划分训练集和测试集的输入和输出\n",
    "train_X, train_y = train[:, :-1], train[:, -1]\n",
    "test_X, test_y = test[:, :-1], test[:, -1]\n",
    "#转化为三维数据\n",
    "# reshape input to be 3D [samples, timesteps, features]\n",
    "train_X = train_X.reshape((train_X.shape[0], 1, train_X.shape[1]))\n",
    "test_X = test_X.reshape((test_X.shape[0], 1, test_X.shape[1]))\n",
    "print(train_X.shape, train_y.shape)\n",
    "print(test_X.shape, test_y.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7f65a19c",
   "metadata": {},
   "source": [
    "# 模型构建及其预测"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "012a2906",
   "metadata": {},
   "source": [
    "* 搭建LSTM模型并绘制损失图\n",
    "    * 本实验使用keras深度学习框架对模型进行快速搭建。建立Sequential模型，向其中添加LSTM层，设定Dropout为0.5，加入Dense层将其维度聚合为1，激活函数使用relu（也用了sigmoid作为激活函数，但实验效果不如relu），损失函数定为均方差Mean Absolute Error(MAE)。优化算法采用Adam，模型采用50个epochs并且每个batch的大小为100。其中：隐藏层有64个神经元，输出层1个神经元（回归问题），输入变量是一个时间步（t-1）的特征。在fit()函数中设置validation_data参数，记录训练集和测试集的损失。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e3ee2975",
   "metadata": {},
   "source": [
    "### 预测一次，并保存预测结构，用于之后的验证"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "b71edde8",
   "metadata": {},
   "outputs": [],
   "source": [
    "checkpoint_save_path = \"./checkpoint/test_4_1.ckpt\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "e85a0f7c",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_save_path,\n",
    "                                                 save_weights_only=True,\n",
    "                                                 save_best_only=True,\n",
    "                                                 monitor='val_loss')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a38a1a38",
   "metadata": {},
   "source": [
    "* LSTM(neurons, input_shape=(input_timesteps, input_dim), return_sequences=return_seq)\n",
    "* Dropout(dropout_rate)\n",
    "* Dense(neurons, activation=activation)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "e41c3d1a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1, 9)"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_X.shape[1], train_X.shape[2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "2738cd6d",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/50\n",
      "2/2 - 8s - loss: 0.4042 - val_loss: 0.3548 - 8s/epoch - 4s/step\n",
      "Epoch 2/50\n",
      "2/2 - 0s - loss: 0.3922 - val_loss: 0.3373 - 125ms/epoch - 63ms/step\n",
      "Epoch 3/50\n",
      "2/2 - 0s - loss: 0.3790 - val_loss: 0.3167 - 133ms/epoch - 67ms/step\n",
      "Epoch 4/50\n",
      "2/2 - 0s - loss: 0.3638 - val_loss: 0.2916 - 150ms/epoch - 75ms/step\n",
      "Epoch 5/50\n",
      "2/2 - 0s - loss: 0.3456 - val_loss: 0.2605 - 128ms/epoch - 64ms/step\n",
      "Epoch 6/50\n",
      "2/2 - 0s - loss: 0.3243 - val_loss: 0.2216 - 160ms/epoch - 80ms/step\n",
      "Epoch 7/50\n",
      "2/2 - 0s - loss: 0.2969 - val_loss: 0.1759 - 137ms/epoch - 69ms/step\n",
      "Epoch 8/50\n",
      "2/2 - 0s - loss: 0.2670 - val_loss: 0.1457 - 370ms/epoch - 185ms/step\n",
      "Epoch 9/50\n",
      "2/2 - 0s - loss: 0.2291 - val_loss: 0.1107 - 147ms/epoch - 73ms/step\n",
      "Epoch 10/50\n",
      "2/2 - 0s - loss: 0.1887 - val_loss: 0.1181 - 79ms/epoch - 40ms/step\n",
      "Epoch 11/50\n",
      "2/2 - 0s - loss: 0.1603 - val_loss: 0.2053 - 95ms/epoch - 48ms/step\n",
      "Epoch 12/50\n",
      "2/2 - 0s - loss: 0.1492 - val_loss: 0.3135 - 74ms/epoch - 37ms/step\n",
      "Epoch 13/50\n",
      "2/2 - 0s - loss: 0.1543 - val_loss: 0.3839 - 79ms/epoch - 40ms/step\n",
      "Epoch 14/50\n",
      "2/2 - 0s - loss: 0.1600 - val_loss: 0.3824 - 82ms/epoch - 41ms/step\n",
      "Epoch 15/50\n",
      "2/2 - 0s - loss: 0.1586 - val_loss: 0.3356 - 69ms/epoch - 35ms/step\n",
      "Epoch 16/50\n",
      "2/2 - 0s - loss: 0.1458 - val_loss: 0.2755 - 70ms/epoch - 35ms/step\n",
      "Epoch 17/50\n",
      "2/2 - 0s - loss: 0.1373 - val_loss: 0.2256 - 79ms/epoch - 40ms/step\n",
      "Epoch 18/50\n",
      "2/2 - 0s - loss: 0.1360 - val_loss: 0.1900 - 70ms/epoch - 35ms/step\n",
      "Epoch 19/50\n",
      "2/2 - 0s - loss: 0.1326 - val_loss: 0.1647 - 73ms/epoch - 37ms/step\n",
      "Epoch 20/50\n",
      "2/2 - 0s - loss: 0.1328 - val_loss: 0.1497 - 65ms/epoch - 33ms/step\n",
      "Epoch 21/50\n",
      "2/2 - 0s - loss: 0.1350 - val_loss: 0.1437 - 74ms/epoch - 37ms/step\n",
      "Epoch 22/50\n",
      "2/2 - 0s - loss: 0.1296 - val_loss: 0.1443 - 78ms/epoch - 39ms/step\n",
      "Epoch 23/50\n",
      "2/2 - 0s - loss: 0.1266 - val_loss: 0.1498 - 76ms/epoch - 38ms/step\n",
      "Epoch 24/50\n",
      "2/2 - 0s - loss: 0.1280 - val_loss: 0.1588 - 84ms/epoch - 42ms/step\n",
      "Epoch 25/50\n",
      "2/2 - 0s - loss: 0.1266 - val_loss: 0.1698 - 72ms/epoch - 36ms/step\n",
      "Epoch 26/50\n",
      "2/2 - 0s - loss: 0.1243 - val_loss: 0.1796 - 82ms/epoch - 41ms/step\n",
      "Epoch 27/50\n",
      "2/2 - 0s - loss: 0.1222 - val_loss: 0.1871 - 75ms/epoch - 38ms/step\n",
      "Epoch 28/50\n",
      "2/2 - 0s - loss: 0.1238 - val_loss: 0.1861 - 82ms/epoch - 41ms/step\n",
      "Epoch 29/50\n",
      "2/2 - 0s - loss: 0.1230 - val_loss: 0.1746 - 73ms/epoch - 37ms/step\n",
      "Epoch 30/50\n",
      "2/2 - 0s - loss: 0.1201 - val_loss: 0.1571 - 68ms/epoch - 34ms/step\n",
      "Epoch 31/50\n",
      "2/2 - 0s - loss: 0.1190 - val_loss: 0.1401 - 65ms/epoch - 33ms/step\n",
      "Epoch 32/50\n",
      "2/2 - 0s - loss: 0.1181 - val_loss: 0.1301 - 74ms/epoch - 37ms/step\n",
      "Epoch 33/50\n",
      "2/2 - 0s - loss: 0.1190 - val_loss: 0.1254 - 81ms/epoch - 41ms/step\n",
      "Epoch 34/50\n",
      "2/2 - 0s - loss: 0.1188 - val_loss: 0.1254 - 74ms/epoch - 37ms/step\n",
      "Epoch 35/50\n",
      "2/2 - 0s - loss: 0.1176 - val_loss: 0.1278 - 69ms/epoch - 35ms/step\n",
      "Epoch 36/50\n",
      "2/2 - 0s - loss: 0.1170 - val_loss: 0.1312 - 73ms/epoch - 37ms/step\n",
      "Epoch 37/50\n",
      "2/2 - 0s - loss: 0.1157 - val_loss: 0.1336 - 71ms/epoch - 36ms/step\n",
      "Epoch 38/50\n",
      "2/2 - 0s - loss: 0.1142 - val_loss: 0.1316 - 70ms/epoch - 35ms/step\n",
      "Epoch 39/50\n",
      "2/2 - 0s - loss: 0.1164 - val_loss: 0.1246 - 68ms/epoch - 34ms/step\n",
      "Epoch 40/50\n",
      "2/2 - 0s - loss: 0.1170 - val_loss: 0.1166 - 69ms/epoch - 35ms/step\n",
      "Epoch 41/50\n",
      "2/2 - 0s - loss: 0.1141 - val_loss: 0.1087 - 134ms/epoch - 67ms/step\n",
      "Epoch 42/50\n",
      "2/2 - 0s - loss: 0.1150 - val_loss: 0.1020 - 313ms/epoch - 156ms/step\n",
      "Epoch 43/50\n",
      "2/2 - 0s - loss: 0.1161 - val_loss: 0.1006 - 192ms/epoch - 96ms/step\n",
      "Epoch 44/50\n",
      "2/2 - 0s - loss: 0.1123 - val_loss: 0.1035 - 82ms/epoch - 41ms/step\n",
      "Epoch 45/50\n",
      "2/2 - 0s - loss: 0.1129 - val_loss: 0.1064 - 87ms/epoch - 43ms/step\n",
      "Epoch 46/50\n",
      "2/2 - 0s - loss: 0.1158 - val_loss: 0.1055 - 90ms/epoch - 45ms/step\n",
      "Epoch 47/50\n",
      "2/2 - 0s - loss: 0.1141 - val_loss: 0.1004 - 130ms/epoch - 65ms/step\n",
      "Epoch 48/50\n",
      "2/2 - 0s - loss: 0.1142 - val_loss: 0.0960 - 139ms/epoch - 70ms/step\n",
      "Epoch 49/50\n",
      "2/2 - 0s - loss: 0.1147 - val_loss: 0.0927 - 135ms/epoch - 68ms/step\n",
      "Epoch 50/50\n",
      "2/2 - 0s - loss: 0.1146 - val_loss: 0.0915 - 128ms/epoch - 64ms/step\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYkAAAEUCAYAAADeJcogAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8/fFQqAAAACXBIWXMAAAsTAAALEwEAmpwYAABUBUlEQVR4nO3deXxU5b348c9ZZsmeyb6xhhAS9kWWomxuYBEFrXvAq9jSXq7XpbXurYpy1dqWn95Wab2tYFstFLWIWoVUVDAihE32LUBCIPs2mcx2zu+PIRGE7Gcyk+R5v168IOGc5zzPBOY7z/Z9JF3XdQRBEAThIuRAV0AQBEEIXiJICIIgCM0SQUIQBEFolggSgiAIQrNEkBAEQRCaJYKEIAiC0CwRJATBDyZMmIDL5erQvZ988gn79u0zuEaC0DFqoCsgCF3t5Zdfxul08tOf/vS87//P//wP69atIyIigqVLlzJy5EiWLFnChx9+SHV1NaGhoZhMJv7617/y+OOPU1FRwbp169i1axc/+MEPWLp0KfPmzQPAYrFgNpsB+NnPfsaBAwcICwsD4NSpUzz11FNMmzat6dmff/45Ho+H6dOn8+mnnzJ58mSysrIuWv/x48eTlpbWbPvcbjdWq5VVq1Z15mUSBEAECUEAfJ/eDx8+zKeffsrGjRt5/PHHWbt2LY8//jiPP/44OTk53HPPPUyZMqXpnuPHj+N2uzl8+HDT9w4cOMChQ4dwOp289957TJw4EVVV+a//+q+mN/0//OEPqOr5//X+8pe/8B//8R8AKIqC1Wpt+juXy9UUcABUVWXNmjUArF27lq+//pqnn376vHo9/PDDBr46Qm8mgoQgAAcPHqRv374oisKUKVMoLCxs9Z7k5GSOHz/OoUOH6Nu3L+B7Aw8JCQEgNDQURVGYNm0a+/fvZ//+/QDExcWRmpraVM6hQ4fYtWsXzz//PODraeTl5fHKK68AviCxatWqpnIbA0xxcTG//vWvsdlszJs3jwMHDrBs2TIyMjIuCEKC0FHiX5IgAJdeeinz588nIiKCu+++m/nz57d6T0ZGBocOHeLw4cNkZGQAkJ6eTnp6OhaLhRkzZlBaWsrvfve7C+6tqKjgF7/4BV6vlyeffJKlS5cydepUAH76059yww03MGnSpGafXVdXx8KFC0lKSuLaa68FYP/+/VxxxRUcP368Iy+BIFyUCBKCAIwcOZLXX3+d559/nrfeeotf/epXXHbZZS3ek56ezuHDh6murmbgwIGA71P/jh07cDgc3HDDDfzyl78E4L333mPv3r2kpaVx/PjxpsDh9XrJyclpChAAtbW15w036bqO2+0+b8gpPDycl156CVVVue2221AUhT/96U9GvRyC0EQECUE4a9y4caxatYq//e1v3HfffeTm5hIVFdXs9enp6bz//vtNw0AAr776Kl9//TVer5e3334bu93e9HdPPPEEP//5zwkJCUGSJAB27drF73//e/74xz82Xbd371527Nhx3pBUREQEb7zxxnnXPPvss0RERDB//nyGDBnCr3/9a06cOMHPfvYzQ14PQQARJAQBgEceeYQ5c+YwadIkbr31Vt58801OnDjB8OHDm70nOTmZHTt2cO211+JwOABYtGgR9957L1OmTMFisVBVVdV0fW1tLVlZWRQUFODxeABfYFq7dm3TNZ9//jkvvfQStbW1/P73vycxMfGiz87MzOS3v/0tsbGxvPHGG/zqV7/ioYceYsyYMVRXVxvwigiCj9gnIQhAfHw8q1evxuv1cuzYMSorK+nfv3+r9/Xv35/09PSmr88dEgJfD+Dee+9l165dhIWFUVhYSGxsLD/84Q8vKOvEiRM8/fTTPPfcc/zsZz9j/vz5F90voes6iqIQHx/Ps88+yyeffMKNN95IZmYm0dHRTdcIghFEkBB6pT//+c+MHj266dfAgQNxu91MmTKFRYsWNQ3ltCY9Pb1pPgJ8cxLFxcU4nU7At8JJVVUeeOABHn30UfLy8liwYAEFBQVNb+S6rrN27VruvPNOHnvsMbKzs5k5cyYPP/wwCxcu5MEHH2Tz5s14vV6Apl4I+IawXnzxRZxOJ8XFxU3fP/caQegMSRw6JAjGqa6u5o477mDGjBksWrSIW265haioKB5++GGys7MBOH36NI899hj33nsvCQkJ3HHHHaSlpfGLX/zivIADUFVVxauvvsru3btZsWIFiqIwfvx4kpOTm62D2+0mLCxMbKYTDCGChCD4UV1dHeHh4S1ec+TIkfOGrFpTXl5ObGxsZ6smCG0igoQgCILQLDEnIQiCIDRLBAlBEAShWSJICIIgCM3qcZvpKivtaFr7p1liY8MpL6/zQ42CW29tN/Tetot29y6ttVuWJWy2sGb/vscFCU3T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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 搭建LSTM模型\n",
    "model = Sequential()\n",
    "\n",
    "model.add(LSTM(100, input_shape=(train_X.shape[1], train_X.shape[2]),return_sequences=True))\n",
    "\n",
    "model.add(Dropout(0.2))\n",
    "\n",
    "model.add(LSTM(100,return_sequences=True))\n",
    "model.add(LSTM(100,return_sequences=False))\n",
    "\n",
    "model.add(Dropout(0.2))\n",
    "\n",
    "model.add(Dense(1,activation='relu'))\n",
    "\n",
    "model.compile(loss='mae', optimizer='adam')\n",
    "\n",
    "if os.path.exists(checkpoint_save_path + '.index'):\n",
    "    print('-------------load the model-----------------')\n",
    "    model.load_weights(checkpoint_save_path)\n",
    "    \n",
    "# fit network\n",
    "history = model.fit(train_X, train_y, epochs=50, batch_size=100, validation_data=(test_X, test_y), verbose=2,shuffle=False,\n",
    "                    validation_freq=1,callbacks=[cp_callback])\n",
    " \n",
    "# 绘制损失图\n",
    "plt.plot(history.history['loss'], label='train')\n",
    "plt.plot(history.history['val_loss'], label='test')\n",
    "plt.title('LSTM损失图', fontsize='12')\n",
    "plt.ylabel('loss', fontsize='10')\n",
    "plt.xlabel('epoch', fontsize='10')\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "134ba838",
   "metadata": {},
   "source": [
    "* 预测并反转数据（反归一化）\n",
    "    * 需要将预测结果和测试集数据组合然后进行比例反转（invert the scaling），同时需要将测试集上的预期值也进行比例转换。 \n",
    "         这里为什么进行比例反转（反归一化）呢？（因为我们将原始数据进行了预处理（连同输出值y），此时的误差损失计算是在处理之后的数据上进行的，为了计算在原始比例上的误差需要将数据进行转化。反转时的矩阵大小一定要和原来的大小（shape）完全相同，否则就会报错。）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "b024ee64",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "operands could not be broadcast together with shapes (36,7) (8,) (36,7) ",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[1;32mC:\\Users\\ADMINI~1\\AppData\\Local\\Temp/ipykernel_10792/1385240735.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      6\u001b[0m \u001b[1;31m#将预测结果按比例反归一化\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      7\u001b[0m \u001b[0minv_y_test\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mconcatenate\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtest_X\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m:\u001b[0m\u001b[1;36m6\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0my_predict\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0maxis\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 8\u001b[1;33m \u001b[0minv_y_test\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mscaler\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minverse_transform\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0minv_y_test\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      9\u001b[0m \u001b[0minv_y_predict\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0minv_y_test\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m-\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     10\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mH:\\deep\\lib\\site-packages\\sklearn\\preprocessing\\_data.py\u001b[0m in \u001b[0;36minverse_transform\u001b[1;34m(self, X)\u001b[0m\n\u001b[0;32m    527\u001b[0m         )\n\u001b[0;32m    528\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 529\u001b[1;33m         \u001b[0mX\u001b[0m \u001b[1;33m-=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmin_\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    530\u001b[0m         \u001b[0mX\u001b[0m \u001b[1;33m/=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mscale_\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    531\u001b[0m         \u001b[1;32mreturn\u001b[0m \u001b[0mX\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mValueError\u001b[0m: operands could not be broadcast together with shapes (36,7) (8,) (36,7) "
     ]
    }
   ],
   "source": [
    "#模型预测收益率\n",
    "y_predict = model.predict(test_X)\n",
    "test_X = test_X.reshape((test_X.shape[0], test_X.shape[2]))\n",
    " \n",
    "# invert scaling for forecast\n",
    "#将预测结果按比例反归一化\n",
    "inv_y_test = np.concatenate((test_X[:, :6],y_predict), axis=1)\n",
    "inv_y_test = scaler.inverse_transform(inv_y_test)\n",
    "inv_y_predict=inv_y_test[:,-1]\n",
    " \n",
    "# invert scaling for actual\n",
    "#将真实结果按比例反归一化\n",
    "test_y = test_y.reshape((len(test_y), 1))\n",
    "inv_y_train = np.concatenate((test_X[:, :6],test_y), axis=1)\n",
    "inv_y_train = scaler.inverse_transform(inv_y_train)\n",
    "inv_y = inv_y_train[:, -1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9220b6f0",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "data = pd.DataFrame({\"反归一化后的预测结果\":inv_y_predict,'反归一化后的真实结果':inv_y})\n",
    "data.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4afb1ae4",
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.plot(inv_y,color='red',label='Original')\n",
    "plt.plot(inv_y_predict,color='green',label='Predict')\n",
    "plt.xlabel('the number of test data')\n",
    "plt.ylabel('close')\n",
    "plt.title('预测与实际数据图')\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7b6485c6",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "from sklearn.metrics import mean_squared_error, mean_absolute_error\n",
    "# 评估\n",
    "# calculate MSE 均方误差 ---> E[(预测值-真实值)^2] (预测值减真实值求平方后求均值)\n",
    "mse = mean_squared_error(inv_y_predict, inv_y)\n",
    "# calculate RMSE 均方根误差--->sqrt[MSE]    (对均方误差开方)\n",
    "rmse = math.sqrt(mean_squared_error(inv_y_predict, inv_y))\n",
    "# calculate MAE 平均绝对误差----->E[|预测值-真实值|](预测值减真实值求绝对值后求均值）\n",
    "mae = mean_absolute_error(inv_y_predict, inv_y)\n",
    "print('均方误差: %.6f' % mse)\n",
    "print('均方根误差: %.6f' % rmse)\n",
    "print('平均绝对误差: %.6f' % mae)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2416ac22",
   "metadata": {},
   "outputs": [],
   "source": [
    "#ACC\n",
    "error = 0\n",
    "summery = 0\n",
    "for i in range(24):\n",
    "    error += abs(inv_y_predict[i] - inv_y[i])\n",
    "    summery += inv_y[i]\n",
    "acc = 1 - error/summery\n",
    "print(\"准确率：{}\".format(acc))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b466deff",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "deep",
   "language": "python",
   "name": "deep"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
